package com.boot2.core.mqtt;

import com.alibaba.fastjson.JSONObject;
import com.boot2.core.model.dto.OnOffLine;
import com.boot2.core.utils.MqttTopicUtil;
import com.boot2.core.utils.StringUtils;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * @author zhangweilin
 * @description: mqtt消息事件
 * @date 2018/12/12
 */
@CommonsLog
public abstract class MqttMessageEvent {

    @Autowired
    MqttProperties mqttProperties;

    /**
     * 包装上下线信息
     *
     * @param jsonObject
     * @param type
     * @return
     */
    private OnOffLine getOnOffLine(JSONObject jsonObject, OnOffLine.Type type) {
        String userName = jsonObject.getString("username");
        String ipaddress = jsonObject.getString("ipaddress");
        String cleanSess = jsonObject.getString("clean_sess");
        Integer protocol = jsonObject.getInteger("protocol");
        Integer connack = jsonObject.getInteger("connack");
        Long ts = jsonObject.getLong("ts");

        //下线特有
        String reason = jsonObject.getString("reason");
        String clientId = jsonObject.getString("clientid");
        OnOffLine onOffLine = createOnOffLineByClientId(clientId, type);

        onOffLine.setUserName(userName);
        onOffLine.setIpaddress(ipaddress);
        onOffLine.setCleanSess(cleanSess);
        onOffLine.setReason(reason);
        onOffLine.setProtocol(protocol);
        onOffLine.setConnack(connack);
        onOffLine.setTs(ts);
        return onOffLine;
    }

    /**
     * 通过clientId创建
     *
     * @param clientId
     * @param type
     * @return
     */
    private OnOffLine createOnOffLineByClientId(String clientId, OnOffLine.Type type) {
        String[] infoArr = clientId.split("_");
        String deviceType = null;
        String version = null;
        String deviceSn = null;
        try {
            deviceType = infoArr[0];
            version = infoArr[1];
            deviceSn = infoArr[2];
        } catch (Exception e) {
//            log.error("非法的客户端连接,clientId:" + clientId);
//            return null;
//            e.printStackTrace();
            throw new IllegalArgumentException("非法的客户端连接,clientId:" + clientId, e);
        }
        String mobilePhone = "";
        if (infoArr.length > 3) {
            mobilePhone = infoArr[3];
        }
        OnOffLine onOffLine = new OnOffLine(type);
        onOffLine.setDeviceSn(deviceSn);
        onOffLine.setDeviceType(deviceType);
        onOffLine.setVersion(version);
        onOffLine.setMobilePhone(mobilePhone);
        return onOffLine;
    }


    /**
     * 非业务层的处理消息
     *
     * @param message
     * @return 是否还需要继续处理业务消息
     */
    public boolean handleMessage(Message<?> message) {
        String mqttTopic = (String) message.getHeaders().get("mqtt_topic");
        //系统消息主题列表
        List<String> sysTopicList = mqttProperties.getInbound().getSysTopics();
        String lwtTopic = mqttProperties.getInbound().getLwtTopic();
        //如果系统主题和遗愿主题都为空，不需要处理
        if (CollectionUtils.isEmpty(sysTopicList) && StringUtils.isEmpty(lwtTopic)) {
            return true;
        }
        //当前主题是否是系统消息主题
        boolean currentSysTopic = false;
        for (int i = 0; i < sysTopicList.size(); i++) {
            String topic = sysTopicList.get(i);
            topic = MqttTopicUtil.getTopicPrefix(topic);
            if (mqttTopic.startsWith(mqttProperties.getMqttTopicsPrefix() + topic)) {
                currentSysTopic = true;
                break;
            }
        }
        //是否是遗愿消息主题
        boolean currentLwtTopic = false;
        lwtTopic = MqttTopicUtil.getTopicPrefix(lwtTopic);
        if (mqttTopic.startsWith(mqttProperties.getMqttTopicsPrefix() + lwtTopic)) {
            currentLwtTopic = true;
        }
        try {
            log.info("mqttTopic: " + mqttTopic);
            Object payload = message.getPayload();
            if (!(payload instanceof String)) {
                return false;
            }
            String json = (String) payload;
            JSONObject jsonObject = null;
            if (currentSysTopic) {
                try {
                    jsonObject = JSONObject.parseObject(json);
                } catch (Exception e) {
                    //            e.printStackTrace();
                    log.warn("转换失败,json: " + json);
                    return false;
                }
                String clientId = jsonObject.getString("clientid");
                //离线
                if (mqttTopic.endsWith("disconnected")) {
                    log.info("设备离线: " + clientId);
                    OnOffLine onOffLine = getOnOffLine(jsonObject, OnOffLine.Type.Offline);
                    handOffLine(onOffLine);
                    //上线
                } else if (mqttTopic.endsWith("connected")) {
                    //上线主题如 :
                    //$SYS/brokers/emq@127.0.0.1/clients/ios_12.1_3daada9a04ef4d9baa37bb23abad615b_15731149741/connected
                    //                String[] topicSecArr=mqttTopic.split("/");
                    //                String info = topicSecArr[4];
                    log.info("设备上线: " + clientId);
                    OnOffLine onOffLine = getOnOffLine(jsonObject, OnOffLine.Type.Online);
                    handOnLine(onOffLine);
                    //下线
                }
                //当前消息为系统消息，不需要当业务消息处理
                return false;
            } else if (currentLwtTopic) {
                //处理遗愿消息
                // 遗愿消息主题类似,可配, /yoju/will/android-clientId
                MqttInboundProperties inbound = mqttProperties.getInbound();
                //遗愿消息主题形如 /yoju/will/#
                try {
                    String[] topicSecArr = mqttTopic.split("/");
                    String info = topicSecArr[3];
//                    String[] infoArr = info.split("_");
//                    String clientId = infoArr[2];
                    OnOffLine onOffLine = createOnOffLineByClientId(info, OnOffLine.Type.Offline);
                    onOffLine.setIsLwtMessage(true);
                    handLwtMessage(onOffLine);
                } catch (Exception e) {
                    log.warn("调用遗愿消息失败,clientId格式应该为android_8.0_2398449tkkfdjbd9822308_18721279166, 实际 mqttTopic:" + mqttTopic,e);
                    //如果主题都不符合规则，就不需要处理了
                    return false;
                }
                //当前消息为遗愿消息，不需要当业务消息处理
                return false;
            }
            return true;
        } catch (Exception e) {
//            e.printStackTrace();
            log.warn("处理系统设备消息失败,无法为您记录系统事件,clientId格式应该为 android_8.0_2398449tkkfdjbd9822308_18721279166,实际 mqttTopic: " + mqttTopic,e);
            //如果主题都不符合规则，就不需要处理了
            return false;
        }
    }

    /**
     * 遗愿消息
     *
     * @param onOffLine
     */
    @Async
    protected abstract void handLwtMessage(OnOffLine onOffLine);

    /**
     * 处理上线事件
     *
     * @param onOffLine
     */
    @Async
    protected abstract void handOnLine(OnOffLine onOffLine);

    /**
     * 处理下线事件
     *
     * @param onOffLine
     */
    @Async
    protected abstract void handOffLine(OnOffLine onOffLine);

}
